package org.finesys.chat.core.base.embedding.store.milvus.filter;

import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import org.finesys.chat.core.base.embedding.filter.Filter;
import org.finesys.chat.core.base.embedding.filter.compairson.EqualFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.GreaterThanEqualFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.GreaterThanFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.InFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.LessThanEqualFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.LessThanFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.LikeFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.NotEqualFilter;
import org.finesys.chat.core.base.embedding.filter.compairson.NotInFilter;
import org.finesys.chat.core.base.embedding.filter.logical.AndFilter;
import org.finesys.chat.core.base.embedding.filter.logical.NotFilter;
import org.finesys.chat.core.base.embedding.filter.logical.OrFilter;

public class MilvusMetadataFilterMapper {

    public MilvusMetadataFilterMapper() {

    }

    public static String map(Filter filter, String metadataFieldName) {
        if (filter instanceof EqualFilter) {
            return mapEqualFilter((EqualFilter) filter, metadataFieldName);
        } else if (filter instanceof NotEqualFilter) {
            return mapNotEqualFilter((NotEqualFilter) filter, metadataFieldName);
        } else if (filter instanceof GreaterThanFilter) {
            return mapGreaterThanFilter((GreaterThanFilter) filter, metadataFieldName);
        } else if (filter instanceof GreaterThanEqualFilter) {
            return mapGreaterThanEqualFilter((GreaterThanEqualFilter) filter, metadataFieldName);
        } else if (filter instanceof LessThanEqualFilter) {
            return mapLessThanEqualFilter((LessThanEqualFilter) filter, metadataFieldName);
        } else if (filter instanceof LessThanFilter) {
            return mapLessThanFilter((LessThanFilter) filter, metadataFieldName);
        } else if (filter instanceof LikeFilter) {
            return mapLikeFilter((LikeFilter) filter, metadataFieldName);
        } else if (filter instanceof InFilter) {
            return mapInFilter((InFilter) filter, metadataFieldName);
        } else if (filter instanceof NotInFilter) {
            return mapNotInFilter((NotInFilter) filter, metadataFieldName);
        } else if (filter instanceof AndFilter) {
            return mapAndFilter((AndFilter) filter, metadataFieldName);
        } else if (filter instanceof OrFilter) {
            return mapOrFilter((OrFilter) filter, metadataFieldName);
        } else if (filter instanceof NotFilter) {
            return mapNotFilter((NotFilter) filter, metadataFieldName);
        } else {
            throw new RuntimeException("不支持的过滤器类型");
        }
    }


    private static String mapEqualFilter(EqualFilter filter, String metadataFieldName) {
        String key = formatKey(filter.getKey(), metadataFieldName);
        return String.format(" %s == %s", key, key, formatValue(filter.getCompairsonValue()));
    }

    private static String mapNotEqualFilter(NotEqualFilter filter, String metadataFieldName) {
        String key = formatKey(filter.getKey(), metadataFieldName);
        return String.format("%s != %s", key, key, formatValue(filter.getCompairsonValue()));
    }

    private static String mapGreaterThanFilter(GreaterThanFilter filter, String metadataFieldName) {
        String key = formatKey(filter.getKey(), metadataFieldName);
        return String.format("%s > %s", key, formatValue(filter.getCompairsonValue()));
    }


    private static String mapGreaterThanEqualFilter(GreaterThanEqualFilter filter, String metadataFieldName) {
        String key = formatKey(filter.getKey(), metadataFieldName);
        return String.format("%s >= %s", key, formatValue(filter.getCompairsonValue()));
    }

    private static String mapInFilter(InFilter filter, String metadataFieldName) {
        return String.format("%s in %s", formatKey(filter.getKey(), metadataFieldName), formatValues(filter.getComparisonValues()));
    }

    private static String mapNotInFilter(NotInFilter filter, String metadataFieldName) {
        String key = formatKey(filter.getKey(), metadataFieldName);
        return String.format("%s not in %s", key, key, formatValues(filter.getComparisonValues()));
    }

    private static String mapLessThanEqualFilter(LessThanEqualFilter filter, String metadataFieldName) {
        String key = formatKey(filter.getKey(), metadataFieldName);
        return String.format("%s <= %s", key, formatValue(filter.getCompairsonValue()));
    }

    private static String mapLessThanFilter(LessThanFilter filter, String metadataFieldName) {
        String key = formatKey(filter.getKey(), metadataFieldName);
        return String.format("%s < %s", key, formatValue(filter.getCompairsonValue()));
    }

    private static String mapLikeFilter(LikeFilter filter, String metadataFieldName) {
        String key = formatKey(filter.getKey(), metadataFieldName);
        return String.format("%s LIKE %s", key, formatValue(filter.getCompairsonValue()));
    }

    private static String mapAndFilter(AndFilter filter, String metadataFieldName) {
        return String.format(" %s and %s", map(filter.getLeft(), metadataFieldName), map(filter.getRight(), metadataFieldName));
    }

    private static String mapOrFilter(OrFilter filter, String metadataFieldName) {
        return String.format(" (%s or %s)", map(filter.getLeft(), metadataFieldName), map(filter.getRight(), metadataFieldName));
    }

    private static String mapNotFilter(NotFilter filter, String metadataFieldName) {
        return String.format(" not( %s)", map(filter.getExpression(), metadataFieldName));
    }

    private static String formatValue(Object value) {
        return !(value instanceof String) && !(value instanceof UUID) ? value.toString() : "'" + String.valueOf(value) + "'";
    }

    private static String formatKey(String key, String metaDataFieldName) {
        return String.format("%s[%s]", metaDataFieldName, key);
    }

    public static List<String> formatValues(Collection<?> values) {
        return (List<String>) values.stream().map(MilvusMetadataFilterMapper::formatValue).collect(Collectors.toList());
    }

}
